﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tracy.DataAccess;
using SharedLib.XmlDataModel;
using Tracy.DataModel;
using System.Xml;
using System.Collections.Specialized;
using SharedLib.Helpers;
using Tracy.Properties;
using Microsoft.Practices.Unity;
using SharedLib;
using Tracy.DataModel.DownloadAdapter;
using Tracy.DataModel.Config;

namespace Tracy.BasicServices
{
    public class DownloadManager : FilterItemProvider<Tracy.BasicServices.DownloadManager.DownloaderSetting>
    {
        public class DownloaderSetting : XmlDataModelWithAttributes, IHasName
        {
            
            /// <summary>
            /// Name of the Downloader
            /// </summary>
            public string Name
            {
                get { return Attributes["name"]; }
                set { Attributes["name"] = value; }
            }

            public string ClassName
            {
                get { return Properties ["class-name"]; }
                set { Properties["class-name"] = value; }
            }

            public DownloaderSetting() : base() { }
            public DownloaderSetting(XmlNode node) : base(node) { }

            public override string RootNodeName
            {
                get
                {
                    return "downloader";
                }
            }
        }

        //private List<IConfigurable> _configurableAdapters;

        //public List<IConfigurable> ConfigurableAdapters
        //{
        //    get {
        //        if (_configurableAdapters == null) _configurableAdapters = new List<IConfigurable>();
        //        return _configurableAdapters; }
        //}
        public event EventHandler<GenericEventArgs<bool>> AutoDownloadModeChanged;
        //public event EventHandler<GenericEventArgs<IConfigurable>> ConfigurablePluginFound;
        private Dictionary<string, IDownloadAdapter> _downloaderDic;
        //Caches the instances of download adapters
        private Dictionary<string, IDownloadAdapter> DownloaderDic
        {
            get {
                if (_downloaderDic == null) _downloaderDic = InitDownloaders();
                return _downloaderDic; 
            }
        }

        private bool _isAutoDownloadMode = false;

        public bool IsAutoDownloadMode
        {
            get { return _isAutoDownloadMode; }
            set {
                if (_isAutoDownloadMode != value)
                {
                    _isAutoDownloadMode = value;
                    AutoDownloadModeChanged.InvokeEvent(this, new GenericEventArgs<bool>(value));
                }
            }
        }

        public DownloadManager()
            : base(@"Settings\Downloaders.xml", "downloaders/downloader")
        {
            
        }

        public void LoadSettings()
        {
            _downloaderDic = InitDownloaders();
        }

        private Dictionary<string, IDownloadAdapter> InitDownloaders()
        {
            Dictionary<string, IDownloadAdapter> downloaderDic = new Dictionary<string, IDownloadAdapter>();
            foreach (XmlElement node in doc.SelectNodes(_itemXPath))
            {
                string adapterName = node.GetAttribute("name");
                foreach (XmlElement typeNode in node.SelectNodes("resource-types/resource-type"))
                {
                    string type = XmlHelper.GetNodeValue(typeNode);
                    if (!downloaderDic.ContainsKey(type) || typeNode.GetAttribute("default") == "true")
                    {
                        string className = XmlHelper.GetNodeValue(node, "class-name");
                        IDownloadAdapter adapter = TracyFacade.Instance.DIContainer.Resolve<IDownloadAdapter>(className);
                        if (adapter is IConfigurable)
                        {
                            ((IConfigurable)adapter).Name = adapterName;
                            TracyFacade.Instance.ConfigurationManager.Attach((IConfigurable)adapter);
                            ////ConfigurablePluginFound.InvokeEvent(this, new GenericEventArgs<IConfigurable>((IConfigurable)adapter));
                            ((IConfigurable)adapter).ConfigChanged += new EventHandler<DataChangedEventArgs<IConfigModel>>(DownloadManager_ConfigChanged);
                        }

                        if (adapter.IsResourceTypeSupported(type))
                        {
                            downloaderDic[type] = adapter;
                        }
                    }
                }
            }
            return downloaderDic;
        }

        void DownloadManager_ConfigChanged(object sender, DataChangedEventArgs<IConfigModel> e)
        {
            IConfigurable adapter = sender as IConfigurable;
            if(adapter != null && adapter is IDownloadAdapter){
                XmlElement node = doc.SelectSingleNode(_itemXPath + "[@name='" + adapter.Name + "']") as XmlElement;
                if (node != null) {

                    TracyFacade.Instance.ConfigurationManager.Update(adapter, e.Data);

                    //Update Downloader Dict
                    foreach (XmlElement typeNode in node.SelectNodes("resource-types/resource-type"))
                    {
                        string type = XmlHelper.GetNodeValue(typeNode);
                        if (!_downloaderDic.ContainsKey(type) || typeNode.GetAttribute("default") == "true")
                        {
                            if (((IDownloadAdapter)adapter).IsResourceTypeSupported(type))
                            {
                                _downloaderDic[type] = (IDownloadAdapter)adapter;
                            }
                        }
                    }
                    
                }
            }
            
        }

        private IDownloadAdapter GetDownloader(string resourceType)
        {
            if (DownloaderDic.ContainsKey(resourceType))
            {
                IDownloadAdapter rtn = DownloaderDic[resourceType];
                return rtn;
            }
            return null;
        }

        public void DownloadResource(Resource resource)
        {
            IDownloadAdapter adapter = GetDownloader(resource.GetResourceType());
            if (adapter != null)
            {
                try
                {
                    adapter.Download(resource, TracyFacade.Instance.UserPreferencesManager.TempPath);
                }
                catch (Exception ex)
                {
                    throw new InvalidOperationException(String.Format("Failed to download resource {0} using {1}", resource.Title, adapter.GetType().Name), ex); 
                }
            }
            //TODO: notify user if not supported
        }

        public string[] GetDownloadingFilePaths(MediaFile file)
        {
            if (file == null || file.Resource == null) return null;
            string fullPath = file.GetDownloadPath();
            if (string.IsNullOrEmpty(fullPath)) return null;

            string type = file.Resource.GetResourceType();
            if (DownloaderDic.ContainsKey(type))
            {
                string[] fileExts = DownloaderDic[type].GetTempFileExts(type);
                string[] rtn = new string[fileExts.Length];
                for (int i = 0; i < rtn.Length; i++)
                {
                    rtn[i] = fullPath + fileExts[i];
                }
                return rtn;
            }
            return null;
            
        }

        public string GetDownloadFolder(MediaFile file)
        {
            if (file == null || file.Resource == null) return TracyFacade.Instance.UserPreferencesManager.TempPath;
            string type = file.Resource.GetResourceType();
            if (DownloaderDic.ContainsKey(type))
            {
                return DownloaderDic[type].GetTempDownloadFolder(TracyFacade.Instance.UserPreferencesManager.TempPath, file);
            }
            return TracyFacade.Instance.UserPreferencesManager.TempPath;
        }

        public string GetValidFileName(string filename, string type)
        {
            if (DownloaderDic.ContainsKey(type))
            {
                return DownloaderDic[type].GetValidFileName(filename);
            }
            return filename;
        }
    }
}
